/*
 * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baidu.fsg.uid.worker;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baidu.fsg.uid.utils.DockerUtils;
import com.baidu.fsg.uid.utils.NetUtils;
import com.baidu.fsg.uid.worker.entity.WorkerNodeEntity;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import java.util.Date;

/**
 * Represents an implementation of {@link WorkerIdAssigner},
 * the worker id will be discarded after assigned to the UidGenerator
 *
 * @author yutianbao
 */
public class DisposableWorkerIdAssigner implements WorkerIdAssigner {

    private static final Log LOGGER = LogFactory.getLog(DisposableWorkerIdAssigner.class);

    private String work_node_rest_url;

    private RestTemplate restTemplate =  new RestTemplate();

    /**
     * Assign worker id base on database.<p>
     * If there is host name & port in the environment, we considered that the node runs in Docker container<br>
     * Otherwise, the node runs on an actual machine.
     *
     * @return assigned worker id
     */
    public long assignWorkerId() {
        // build worker node entity
        return this.getWorkerNodeId();
    }

    /**
     * Build worker node entity by IP and PORT
     */
    private WorkerNodeEntity buildWorkerNode() {

        WorkerNodeEntity workerNodeEntity = new WorkerNodeEntity();
        //程序运行目录
        workerNodeEntity.setDir(this.getClass().getResource("/").getPath());

        if (DockerUtils.isDocker()) {
            workerNodeEntity.setType(WorkerNodeType.CONTAINER.value());
            workerNodeEntity.setIp(DockerUtils.getDockerHost());
            workerNodeEntity.setHostName(DockerUtils.getDockerHost());
            workerNodeEntity.setPort(DockerUtils.getDockerPort());
        } else {
            workerNodeEntity.setType(WorkerNodeType.ACTUAL.value());
            workerNodeEntity.setIp(NetUtils.getLocalAddress());
            workerNodeEntity.setHostName(NetUtils.getLocalHostName());
            workerNodeEntity.setPort(String.valueOf(System.currentTimeMillis()));
        }

        return workerNodeEntity;
    }

    /**
     * 调用远程 http 获取 node id
     *
     * @return NodeId
     */
    private long getWorkerNodeId() {

        try {


            //当前程序运行环境信息
            WorkerNodeEntity workerNodeEntity = buildWorkerNode();
            workerNodeEntity.setLaunchDate(new Date());
            workerNodeEntity.setCreated(new Date());
            workerNodeEntity.setModified(new Date());

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);

            HttpEntity<String> formEntity = new HttpEntity<>(JSON.toJSONString(workerNodeEntity), headers);
            LOGGER.info("Add worker node:" + JSON.toJSONString(workerNodeEntity));

            String result = restTemplate.postForEntity(work_node_rest_url, formEntity, String.class).getBody();
            //result: {"code":200,"message":"SUCCESS","data":22}
            LOGGER.info("Get worker node:" + result);

            JSONObject object = JSONArray.parseObject(result);

            if(object.containsKey("code")){
                if("200".equals(object.getString("code"))){
                   if(object.containsKey("data")){
                       return Long.parseLong(object.getString("data"));
                   }
                }
            }

            throw new RuntimeException("getWorkerNodeId is error...");

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }

    }

    public void setWork_node_rest_url(String work_node_rest_url) {
        this.work_node_rest_url = work_node_rest_url;
    }

}
